﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RaytracerLib.MathLib.Polynomials;

namespace RaytracerLib.MathLib.PolynomialFunction
{
    public class PolynomialFunction
    {
        private Element m_tree;
        private Func<Vector3, Vector3> m_gradient;
        private Func<Vector3, double> m_evaluator;
        private Func<Vector3, Vector3, Polynomial> m_intersection;

        public PolynomialFunction(string a_function)
        {
            IEnumerable<Element> rpn_elements = StringToRPN.Parse(a_function);
            m_tree = RPNToTree.Build(rpn_elements);
        }

        private PolynomialFunction(Element a_tree)
        {
            m_tree = a_tree;
        }

        public Func<Vector3, Vector3, Polynomial> Intersection
        {
            get
            {
                if (m_intersection == null)
                    m_intersection = TreeCompiler.CompileIntersectionPolynomial(m_tree);

                return m_intersection;
            }
        }

        public PolynomialFunction DiffrentiateX()
        {
            return new PolynomialFunction(TreeTransforms.Simplify(
                TreeTransforms.Diffrentiate(m_tree, VariableSymbol.X)));
        }

        public PolynomialFunction DiffrentiateY()
        {
            return new PolynomialFunction(TreeTransforms.Simplify(
                TreeTransforms.Diffrentiate(m_tree, VariableSymbol.Y)));
        }

        public PolynomialFunction DiffrentiateZ()
        {
            return new PolynomialFunction(TreeTransforms.Simplify(
                TreeTransforms.Diffrentiate(m_tree, VariableSymbol.Z)));
        }

        public Func<Vector3, Vector3> Gradient
        {
            get
            {
                if (m_gradient == null)
                    m_gradient = TreeCompiler.CompilePolynomialGradient(m_tree);

                return m_gradient;
            }
        }

        public double Evaluate(Vector3 a_point)
        {
            if (m_evaluator == null)
                m_evaluator = TreeCompiler.CompilePolynomialFunction(m_tree);

            return m_evaluator(a_point);
        }

        public override string ToString()
        {
            return m_tree.ToString();
        }

        public PolynomialFunction Expand()
        {
            return new PolynomialFunction(TreeTransforms.Expand(m_tree.CloneTree(), true, true));
        }
    }
}
